﻿using CCLog;
using CommonEntity.CommonImageEntities;
using CommonEntity.Handlers;
using OpenCVInfras;
using OpenCvSharp;
using ScienceAppService.Entities;
using ScienceAppService.ModuleInterface;
using ScienceAppService.RpcUtils;
using ScienceRpcServe.Protos;
using System.Threading.Tasks;
using ScienceAppService.Utils;
using Point3d = CommonEntity.CommonImageEntities.Point3d;

namespace ScienceAppService.ModuleService;


/// <summary>
/// todo 将 show 和 split 分开
/// </summary>
public class ImageShowService : IImageShowService
{
    #region 私有变量

    private ImageInfo _imageInfo;
    
    private ImageShow.ImageShowClient _rpcClient;

    private ILoggerService _logger;

    private ImageOrientationEnum _imageOrientation;

    // 相同朝向 100ms 内只准请求一次
    private DateTime _date;

    #endregion
    public ImageShowService(ILoggerService logger)
    {
        _imageOrientation = ImageOrientationEnum.None;
        _rpcClient = RpcConfigure.Instance.GetImageShowClient();
        _logger = logger;
    }
    
    public event CommonHandler<FrushMats>? FrushMatsEvent;

    public event CommonHandler<CrossLineMat>? FrushCrosslineMatsEvent;

    public event CommonHandler<CrossLineInfo>? FrushCrosslineInfoEvent;

    public event CommonHandler<object?> WindowAdjustChangeEvent;

    public event CommonHandler<string> FrushSeriesDescriptionEvent;

    public event CommonHandler<ImageInfo>? FrushImageInfoEvent;

    public event CommonHandler<string>? AlarmEvent;

    public event CommonHandler<Mat>? FrushTagMatEvent;

    public async Task FrushMats(int index, ImageOrientationEnum mprType)
    {
        try
        {
            if (mprType == ImageOrientationEnum.None || mprType == ImageOrientationEnum.ThreeD) return;

            if (_imageOrientation == mprType && DateTime.Now - _date <= new TimeSpan(0, 0, 0, 0, 100)) return;
            _date = DateTime.Now;
            _imageOrientation = mprType;

            var rs = await _rpcClient.GetMatsAsync(new MatRequest()
            {
                Orientation = mprType.ConvertToProtoOrientation(),
                Index = index,
            });

            if (!string.IsNullOrEmpty(rs.Remark))
            {
                AlarmEvent?.Invoke(rs.Remark);
                return;
            }

            var mats = new FrushMats
            {
                CtImage = rs.OriginMat.ConvertToMat(),
                Count = rs.Count,
                CurrentIndex = rs.CurrentIndex,
                Orientation = rs.Orientation.ConvertToImageOrientation()
            };

            switch (mprType)
            {
                case ImageOrientationEnum.TransversePlane:
                    mats.LableMat = AppServiceEnv.DrawAxMatDic.Keys.Contains(index) ? AppServiceEnv.DrawAxMatDic[index] : AppCvUtil.PaintMaskByVal(rs.LableMat.ConvertToMat());
                    break;
                case ImageOrientationEnum.SagittalPlane:
                    mats.LableMat = AppServiceEnv.DrawSagMatDic.Keys.Contains(index) ? AppServiceEnv.DrawSagMatDic[index] : AppCvUtil.ResizeLabelMat(AppCvUtil.PaintMaskByVal(rs.LableMat.ConvertToMat()), 
                        mats.CtImage!.Height);
                    break;
                case ImageOrientationEnum.CoronalPlane:
                    mats.LableMat = AppServiceEnv.DrawCorMatDic.Keys.Contains(index) ? AppServiceEnv.DrawCorMatDic[index] : AppCvUtil.ResizeLabelMat(AppCvUtil.PaintMaskByVal(rs.LableMat.ConvertToMat()), 
                        mats.CtImage!.Height);
                    break;
            }

            FrushMatsEvent?.Invoke(mats);
        }
        catch (Exception e)
        {
            _logger.Error(nameof(FrushMats), e.Message);
        }
    }

    public async Task FrushAllOrientationMats(Point3d p)
    {
        await FrushMats((int)p.Z, ImageOrientationEnum.TransversePlane);
        await FrushMats((int)p.X, ImageOrientationEnum.SagittalPlane);
        await FrushMats((int)p.Y, ImageOrientationEnum.CoronalPlane);
    }

    public async Task<int> GetCtVal(int[] p)
    {
        var request = new PointRequest();
        request.Point = new ScienceRpcServe.Protos.Point3d();
        request.Point.X = p[0];
        request.Point.Y = p[1];
        request.Point.Z = p[2];
        var ctVal = await _rpcClient.GetCtValAsync(request);
        return ctVal.Value;
    }

    /// <summary>
    /// 十字线刷新
    /// </summary>
    /// <param name="p"></param>
    /// <param name="orientation"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public async Task FrushCrossLine(int[] p)
    {

        if (AppServiceEnv.ImageInfo == null) return;

        var request = new PointRequest();
        request.Point = new ScienceRpcServe.Protos.Point3d();
        request.Point.X = p[0];
        request.Point.Y = p[1];
        request.Point.Z = p[2];
        var ctVal = await _rpcClient.GetCtValAsync(request);

        // 信息数据刷新
        FrushCrosslineInfoEvent?.Invoke(new CrossLineInfo() { X = p[0], Y = p[1], Z = p[2], CtVal = ctVal.Value });

        // 绘制 mpr 十字线
        var crossLineMats = new CrossLineMat() { Point = p};

        // 横断面
        //if (PaintCrossLineService.IsPointIsValid(new int[] { p[0], p[1] },
        //    new OpenCvSharp.Size(AppServiceEnv.ImageInfo.Width, AppServiceEnv.ImageInfo.Height)))
        //{
            crossLineMats.AxCrossMat = PaintCrossLineService.PaintCrossLine(new int[] { p[0], p[1] },
            new OpenCvSharp.Size(AppServiceEnv.ImageInfo.Width, AppServiceEnv.ImageInfo.Height));
        //}

        // 矢状面
        //if (PaintCrossLineService.IsPointIsValid(new int[] { p[1], p[2] },
        //    new OpenCvSharp.Size(AppServiceEnv.ImageInfo.Height, AppServiceEnv.ImageInfo.Count)))
        //{
            crossLineMats.SagCrossMat = PaintCrossLineService.PaintCrossLine(new int[] { p[1], (int)(p[2] * AppServiceEnv.ImageInfo.ImageFactor) },
            new OpenCvSharp.Size(AppServiceEnv.ImageInfo.Height, AppServiceEnv.ImageInfo.Count * AppServiceEnv.ImageInfo.ImageFactor));
        //}

        // 冠状面
        //if (PaintCrossLineService.IsPointIsValid(new int[] { p[0], p[2] },
        //    new OpenCvSharp.Size(AppServiceEnv.ImageInfo.Width, AppServiceEnv.ImageInfo.Count)))
        //{
            crossLineMats.CorCrossMat = PaintCrossLineService.PaintCrossLine(new int[] { p[0], (int)(p[2] * AppServiceEnv.ImageInfo.ImageFactor) },
            new OpenCvSharp.Size(AppServiceEnv.ImageInfo.Width, AppServiceEnv.ImageInfo.Count * AppServiceEnv.ImageInfo.ImageFactor));
        //}

        FrushCrosslineMatsEvent?.Invoke(crossLineMats);
    }

    /// <summary>
    /// 使用 nii.gz 文件
    /// </summary>
    /// <param name="currentSeries"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public Task SetImageFile(SplitSeriesInfo currentSeries)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="gzFiles"></param>
    /// <returns></returns>
    public async Task SetNiiGzFile(string dir)
    {
        try 
        {
            var niigzs = new DirectoryInfo(dir).GetFiles().Where(fi => 
                                                                       fi.Name.EndsWith(".nii.gz", StringComparison.OrdinalIgnoreCase) ||
                                                                       fi.Extension.Equals(".mha", StringComparison.OrdinalIgnoreCase)).Select(fi=>fi.FullName).ToList();

            var request = new SetGzFileRequest();
            request.SegGzFile = niigzs.FirstOrDefault(nii => nii.ToLower().Contains("mask")) ?? "";
            request.OriginGzFile = niigzs.FirstOrDefault(nii => !nii.ToLower().Contains("mask")) ?? "";

            var rs = await _rpcClient.SetNiiGzFileAsync(request);
            if (!string.IsNullOrEmpty(rs.Remark))
            {
                AlarmEvent?.Invoke(rs.Remark);
            }

            //// 获取图像信息
            //var infoRs = await _rpcClient.GetImageInfoAsync(new EmptyRequest());

            //if (!string.IsNullOrEmpty(infoRs.Remark))
            //{
            //    AlarmEvent?.Invoke(infoRs.Remark);
            //    return;
            //}

            //_imageInfo = infoRs.ToImageInfo();
            //AppServiceEnv.ImageInfo = _imageInfo;
            //FrushImageInfoEvent?.Invoke(_imageInfo);
        }
        catch 
        {
            AlarmEvent?.Invoke("nii.gz文件设置失败");
        }
    }

    public async Task SetImageInfo()
    {
        try
        {
            var rs = await _rpcClient.GetImageInfoAsync(new EmptyRequest());

            if (!string.IsNullOrEmpty(rs.Remark))
            {
                AlarmEvent?.Invoke(rs.Remark);
                return;
            }

            _imageInfo = rs.ToImageInfo();
            AppServiceEnv.ImageInfo = _imageInfo;
            FrushImageInfoEvent?.Invoke(_imageInfo);
            FrushSeriesDescriptionEvent?.Invoke(rs.SeriesDescription);
        }
        catch (Exception e)
        {
            _logger.Error(nameof(SetImageInfo), e.Message);
        }

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="startVal"></param>
    /// <param name="endVal"></param>
    /// <returns></returns>
    public async Task AdjustWindow(int startVal, int endVal)
    {
        try
        {
            var rs = await _rpcClient.AdjustWindowAsync(new WindowCenterAndWidthRequest(){WindowMin = startVal,WindowMax = endVal});

            if (!string.IsNullOrEmpty(rs.Remark))
            {
                AlarmEvent?.Invoke(rs.Remark);
            }
            WindowAdjustChangeEvent?.Invoke(null);
        }
        catch (Exception e)
        {
            _logger.Error(nameof(AdjustWindow), e.Message);
        }
    }

    public async Task<Mat> GetTagInfoMat()
    {

        var tags = await _rpcClient.GetTagInfoAsync(new EmptyRequest());

        if (!string.IsNullOrEmpty(tags.Remark))
        {
            AlarmEvent?.Invoke(tags.Remark);
            return new Mat();
        }

        var mat = AppCvUtil.PaintTagMat(tags);

        FrushTagMatEvent?.Invoke(mat);

        return mat;
    }

}
